package sigma;
import java.util.ArrayList;
import java.io.*;

/*
 * Figure out state variable declarations
 * Figure out how to get all patient types and populate route.dat
 * No timing data
 */

public class MakeSimulation {
    ArrayList<Activity> _activities = new ArrayList<Activity>();
    int _numOfPatientTypes = 1067;
    int _numOfProcedures = 5;
    
    static int _startActivityType = 1;
    static int _endActivityType = 2;
    static int _sortActivityType = 3;
    static int _arriveActivityType = 4;
    static int _leaveActivityType = 5;
    static int _runActivityType = 6;
    static int _initActivityType = 7;
    
    public MakeSimulation() {
        //Get all patient types and populate their respective ROUTE.DAT
        initialize();
        
        //Create start/finish (activities) for each procedure
        for (int procedureCounter = 1; procedureCounter <= _numOfProcedures; procedureCounter++) {
            makeProcedure(procedureCounter);
        }
        
        //Make sort node
        makeSortNode();
        
        //Make leave node
        makeLeaveNode();
        
        //Make arrive node
        makeArriveNode();
        
        //Make init node
        makeInitNode();
        
        //Make run node
        makeRunNode();
        
        //Determine timing for those procedures
        
        //Write all activities to C
        output();
    }
    
    public void initialize() {
        //Read data
        
        //Generate DAT files
    }
    
    public void makeProcedure(int ID) {
        Activity startActivity = new Activity(_startActivityType, ID);
        _activities.add(startActivity);
        
        Activity endActivity = new Activity(_endActivityType, ID);
        _activities.add(endActivity);
    }
    
    public void makeSortNode() {
        Activity sortActivity = new Activity(_sortActivityType, _numOfProcedures);
        _activities.add(sortActivity);
    }   
    
    public void makeArriveNode() {
        Activity arriveActivity = new Activity(_arriveActivityType, _numOfPatientTypes);
        _activities.add(arriveActivity);
    }
    
    public void makeLeaveNode() {
        Activity arriveActivity = new Activity(_leaveActivityType, 0);
        _activities.add(arriveActivity);
    }
    
    public void makeInitNode() {
        Activity arriveActivity = new Activity(_initActivityType, 0);
        _activities.add(arriveActivity);
    }
    
    public void makeRunNode() {
        Activity arriveActivity = new Activity(_runActivityType, 0);
        _activities.add(arriveActivity);
    }
    
    public void output() {
        try {
            FileWriter outFile = new FileWriter("sim.c");
            PrintWriter out = new PrintWriter(outFile);

            //includes
            out.println("#include \"sigmafns.h\"");
            out.println("#include \"sigmalib.h\"");
            out.println();
            
            //List event functions used in the simulation model
            out.println("/* EVENT FUNCTIONS USED IN THE SIMULATION MODEL */");
            for(Activity activity:_activities) {
                out.println("void " + activity.getStartNodeName() + "(void);");
            }
            out.println();
            
            //State variable declarations
            out.println("/*   STATE VARIABLE DELARATIONS   */");
            out.println("long PMAX;");
            out.println("long PRDMAX;");
            out.println("long PDATA;");
            out.println("long PRDDATA;");
            out.println("long NEXTPRD;");
            out.println("long QT;");
            out.println("long PTYPE;");
            out.println("long ITER;");
            out.println("long PID;");
            out.println("long QPRD[100];");
            out.println("long STAFF;");
            out.println("long PRIORITY;");
            out.println("long QLEAVE;");
            out.println();
            
            //Enumerate all the event functions
            out.println("/*   EVENT FUNCTIONS   */");
            out.println("enum {");
            out.println("run_end_event,");
            for(Activity activity:_activities) {
                out.println(activity.getStartNodeName() + "_event,");
            }
            out.println("};");
            out.println();
            
            //main
            out.println("/*    MAIN PROGRAM     */");
            out.println("int main(int argc, char** argv) {");
            out.println("int  next_event;");
            out.println("char keytoclose = 'p';");
            out.println();
            out.println("if(!startup_check(0))");
            out.println("return -1;");
            out.println();
            out.println("/* Initialize csiglib and simulation */");
            out.println("while (initialize(argc, (const char * *)argv)) {;");
            out.println();
            out.println("/* Schedule beginning of simulation */");
            out.println("event_time = current_time;");
            out.println("event_type = RUN_event;");
            out.println("schedule_event();");
            out.println();
            out.println("/* Schedule end of simulation */");
            out.println("event_time = stop_time;");
            out.println("event_type = run_end_event;");
            out.println("event_priority = 9999;");
            out.println("schedule_event();");
            out.println();
            out.println("/* EVENT EXECUTION CONTROL LOOP */");
            out.println("while (!run_error && !done) {");
            out.println("/* Pull next event from event list */");
            out.println("next_event = c_timing();");
            out.println();
            out.println("/* increment the event count for this event */");
            out.println("event_count[next_event]++;");
            out.println();
            out.println("/* Call appropriate event routine */");
            out.println("switch ( next_event ) {");
            out.println("case run_end_event:  run_end();");
            out.println("break;");
            out.println();
            
            for (Activity activity:_activities) {
                out.println("case " + activity.getStartNodeName() + "_event: " + activity.getStartNodeName() + "();");
                out.println("event_trace(\"" + activity.getStartNodeName() + "\",event_count[next_event]);");
                out.println("break;");
                out.println();
            }
            out.println("}");
            out.println("}");
            out.println("}");
            out.println("// experiments terminated");
            out.println("return 0;");
            out.println("}");
            out.println();            
            
            //event_trace
            out.println("void event_trace(const char * name_of_event,const long count) {");
            out.println("c_timest(QT, 1, 0);");
            out.println("c_sampst(QT, 1, 0);");
            out.println("if(trace_flag) fprintf(output_fp, \"%9.3f\t %6s\t%6d \",current_time,name_of_event,count);");
            out.println("if(trace_flag) fprintf(output_fp, \"	%7.3g \n\"");
            out.println(",(double)QT);");
            out.println("}");
            out.println();
            
            //initialize
            out.println("int initialize (int argc, const char** argv) {");
            out.println("static int first_time = 1;");
            out.println("static FILE *input_fp; ");
            out.println("char *exp_file_name;");
            out.println("char y_n = 'p';");
            out.println();
            out.println("char dir[256];");
            out.println("char fname[256];");
            out.println("char ext[256];");
            out.println("char simulation[1024];");
            out.println("char experient_name[1024];");
            out.println("_splitpath( argv[0], NULL, dir, fname, ext );");
            out.println("strcpy(simulation, fname);");
            out.println("strcat(simulation, ext);");
            out.println("strcpy(experient_name, fname);");
            out.println("strcat(experient_name, \".exp\");");
            out.println("printf(\"Running the simulation: %s\n\", simulation);");
            out.println("if(strlen(dir) !=0)");
            out.println("printf(\"In Path: %s\n\",dir);");
            out.println("if (first_time) {");
            out.println("exp_file_name = _strdup(argv[0]);");
            out.println("exp_file_name[strlen(exp_file_name)-1] = 'p';");
            out.println("printf(\"\nLooking for experiment file: %s\n\",experient_name);");
            out.println("}");
            out.println("");
            out.println("if ((first_time && (input_fp=fopen(exp_file_name,\"r\"))!=NULL) || input_fp!=NULL) {");
            out.println("if (first_time) {");
            out.println("first_time = 0; /* Reset for next time into initialize */");
            out.println("printf(\"Found. Use [Control]-C to abort replications.\n\");");
            out.println("}");
            out.println("");
            out.println("/* We have run control file of type *.exp */");
            out.println("/* Read next set of data from run control file. */");
            out.println("if (fscanf(input_fp,\"%s %1s %ld %lf %d\", output_file_name, &y_n, &rndsd, &stop_time, &trace_flag)<4) {");
            out.println("/* End of run control file */");
            out.println("fclose(input_fp);");
            out.println("return 0;");
            out.println("}");
            out.println("");
            out.println("done = 0;");
            out.println("}");
            out.println("}");
            out.println();
            
            //run_end()
            out.println("void run_end() {");
            out.println("printf(\"\r\nNormal completion after %f time units\n\",current_time);");
            out.println("printf(\"The Next Seed In the Random Input Stream is %ld\n\",rndsd);");
            out.println();
            out.println("///  Summary statistics ///");
            out.println("fprintf(output_fp,\"SUMMARY STATISTICS\n\");");
            out.println("printf(\"SUMMARY STATISTICS\n\");");
            out.println("c_timest(QT, 1, 1);");
            out.println("fprintf(output_fp, \"QT:\n Time Ave. = \t%7.4g Time Sample Var. =\t%7.4g\n\", transfer[4], transfer[7]);");
            out.println("c_sampst(QT, 1, 1);");
            out.println("fprintf(output_fp, \" Event Ave. =\t%7.4g Event Sample Var. =\t%7.4g\n\", transfer[4], transfer[8]);");
            out.println("fprintf(output_fp, \" Minimum =\t%7.4g\n\", transfer[7]);");
            out.println("fprintf(output_fp, \" Maximum =\t%7.4g\n\", transfer[6]);");
            out.println("printf(\" Event Ave.  = 	%7.4g Event Sample Var.= 	%7.4g\n\", transfer[4], transfer[8]);");
            out.println("printf(\" Minimum  = 	%7.4g\n\", transfer[7]);");
            out.println("printf(\" Maximum  = 	%7.4g\n\", transfer[6]);");
            out.println("printf(\"Output written to, %s\n\",output_file_name);");
            out.println("fclose(output_fp);");
            out.println("c_closedisk();");
            out.println("done = 1;");
            out.println("}");
            out.println();
            out.println();
            out.println();
            out.println();
            out.println();
            
            //Event Functions
            out.println("/****************************/");
            out.println("/*     EVENT FUNCTIONS      */");
            out.println("/****************************/");
            out.println();
            
            //For every activity, put it in a temporary text file and output that stuff
            for(Activity activity:_activities) {
                activity.outputToText(activity.getStartNodeName() + ".txt");
                //Somehow append that file to this file
                out.println();
            }
            
            out.close();
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }
}



